/*
 * Created by SharpDevelop.
 * User: 81786
 * Date: 04.12.2007
 * Time: 13:21
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Diagnostics;
using Microsoft.Research.CommunityTechnologies.Treemap;

namespace MemTreeMap
{
	/// <summary>
	/// Description of MainForm.
	/// </summary>
	public partial class MainForm : Form
	{
		public ulong sysMem = 0;
		public int selectedProcessId = -1;
		public int zoomedProcessId = -1;
		
		[STAThread]
		public static void Main(string[] args)
		{
			Application.EnableVisualStyles();
			Application.SetCompatibleTextRenderingDefault(false);
			Application.Run(new MainForm());
		}
		
		public MainForm()
		{
			//
			// The InitializeComponent() call is required for Windows Forms designer support.
			//
			InitializeComponent();
			
			// Physical system memory
			System.Management.SelectQuery selectQuery
			= new System.Management.SelectQuery("Win32_ComputerSystem");
			System.Management.ManagementObjectSearcher searcher
			= new System.Management.ManagementObjectSearcher(selectQuery);
			foreach (System.Management.ManagementObject comp in searcher.Get())
			{
				sysMem += ((UInt64)(comp["TotalPhysicalMemory"]));
			}
			totalMemStatusLabel.Text = FormatMemString((long)sysMem);
			
			treemapControl.NodeColorAlgorithm = NodeColorAlgorithm.UseColorMetric;
			
			BuildProcessTreemap();
			setUpdateTimer();
		}	
		void RefreshButtonClick(object sender, EventArgs e)
		{
			BuildProcessTreemap();
		}
		
		string FormatMemString(long mem)
		{
			return String.Format("{0:#,#} KB", mem/1024);
		}
		
		void updateSpeedItemClicked(object sender, ToolStripItemClickedEventArgs e)
		{
			if (e.ClickedItem is ToolStripMenuItem)
			{
				ToolStripDropDownButton menu = (ToolStripDropDownButton)sender;
				foreach (ToolStripItem item in menu.DropDownItems)
				{
					if (item is ToolStripMenuItem)
					{
						((ToolStripMenuItem)item).Checked = false;
					}
				}	
				
				ToolStripMenuItem selection = (ToolStripMenuItem)e.ClickedItem;
				selection.Checked = true;
				
				setUpdateTimer();
			}
		}
		
		void setUpdateTimer()
		{
			ToolStripMenuItem selection = (ToolStripMenuItem)updateSpeedDropDownButton.DropDownItems[0];
			foreach (ToolStripItem item in updateSpeedDropDownButton.DropDownItems)
			{
				if (item is ToolStripMenuItem)
				{
					if ( true == ((ToolStripMenuItem)item).Checked)
					{
						selection = (ToolStripMenuItem)item;
					}
				}
			}	
				
			int interval = 1000;
			switch(selection.Text)
			{
				case "0.5 s":
					interval = 500;
					break;
				case "1 s":
					interval = 1000;
					break;
				case "2 s":
					interval = 2000;
					break;
				case "5 s":
					interval = 5000;
					break;
				case "10 s":
					interval = 10000;
					break;
				case "Paused":
					interval = -1000;
					updateTimer.Enabled = false;
					break;
			}
			updateTimer.Interval = interval;
			if (-1000 != interval)
			{
				updateTimer.Enabled = true;
			}
		}
		
		void updateMap(object sender, EventArgs e)
		{
			if (-1 == zoomedProcessId)
			{
				BuildProcessTreemap();
			}
			else
			{
				BuildDllTreemap(zoomedProcessId);
			}
		}
		
		void TreemapControlSelectedNodeChanged(object sender, EventArgs e)
		{
			TreemapControl treemapControl = (TreemapControl)sender;
			
			if (-1 == zoomedProcessId && null != treemapControl.SelectedNode)
			{
				zoomInButton.Enabled = (-1 != (int)treemapControl.SelectedNode.Tag);
				selectedProcessId = (int)treemapControl.SelectedNode.Tag;
			}
			else
			{
				selectedProcessId = -1;
			}
		}
		
		void zoomInButtonClick(object sender, EventArgs e)
		{
			zoomedProcessId = (int)treemapControl.SelectedNode.Tag;
			if (BuildDllTreemap(zoomedProcessId))
			{
				zoomInButton.Enabled = false;
				zoomOutButton.Enabled = true;
			}
			else
			{
				zoomedProcessId = -1;
			}
		}
		
		void zoomOutButtonClick(object sender, EventArgs e)
		{
			if (-1 != zoomedProcessId)
			{
				BuildProcessTreemap();
				
				zoomedProcessId = -1;
				zoomOutButton.Enabled = false;
			}
		}
		
		void BuildProcessTreemap()
		{
			long usedMem = 0;
			
			treemapControl.BeginUpdate();
			treemapControl.MaxColorMetric = sysMem/5.0F;
			int tmpSelectedProcessId = selectedProcessId;
			treemapControl.Clear();	// selection changed is triggered
			Process[] processes = Process.GetProcesses();
			string str = String.Empty;
			long mem = 0;
			Nodes nodes = treemapControl.Nodes;
			Node node;
			Node selectionNode = null;
			foreach(Process process in processes)
			{
				mem = process.PrivateMemorySize64;
				usedMem += mem;
				
				str = process.ProcessName + "\n" + FormatMemString(mem);
				node = nodes.Add(str, mem, mem, process.Id);
				node.ToolTip = str;
				if (process.Id == tmpSelectedProcessId)
				{
					selectionNode = node;
				}
			}
			if (freeMemStripButton.Checked)
			{
				long freeMem = (long)sysMem-usedMem;
				nodes.Add("Free memory\n"+FormatMemString(freeMem), freeMem, -1, -1);
			}
			if (null != selectionNode)
			{
				treemapControl.SelectNode(selectionNode);
			}
			else
			{
				selectedProcessId = -1;
			}
			treemapControl.EndUpdate();
			
			usedMemStatusLabel.Text = FormatMemString(usedMem);
			freeMemStatusLabel.Text = FormatMemString((long)sysMem-usedMem);
		}
		
		bool BuildDllTreemap(int ProcessId)
		{
			if (-1 == ProcessId)
			{
				return false;
			}
			Process process = Process.GetProcessById(ProcessId);
			if (null == process)
			{
				return false;
			}
			
			treemapControl.BeginUpdate();
			treemapControl.MaxColorMetric = process.PrivateMemorySize64/10.0F;
			treemapControl.Clear();	// selection changed is triggered
			
			ProcessModuleCollection processModuleCollection = process.Modules;
			Nodes nodes = treemapControl.Nodes;
			Node node;
			string str = String.Empty;
			int mem = 0;
			ProcessModule mainModule = process.MainModule;
			foreach(ProcessModule processModule in processModuleCollection)
			{
				mem = processModule.ModuleMemorySize;
				str = processModule.ModuleName + "\n" + FormatMemString(mem);
				node = nodes.Add(str, mem, (processModule.ModuleName == mainModule.ModuleName) ? -1 : mem);
				node.ToolTip = str;
			}
			
			treemapControl.EndUpdate();
			
			return true;
		}
		
		void TreemapControlNodeDoubleClick(object sender, Microsoft.Research.CommunityTechnologies.Treemap.NodeEventArgs nodeEventArgs)
		{
			zoomInButtonClick(sender, nodeEventArgs);
		}
		
		void TreemapControlNodeMouseUp(object sender, NodeMouseEventArgs nodeMouseEventArgs)
		{
			if (MouseButtons.Right == nodeMouseEventArgs.Button)
			{
				zoomOutButtonClick(null, new EventArgs());
			}
		}
		
		void FreeMemStripButtonClick(object sender, EventArgs e)
		{
			if (-1 == zoomedProcessId)
			{
				BuildProcessTreemap();
			}
		}
	}
}
